package quoridorDecisionMaker;

import quoridor.Action;
import quoridor.Board;
import quoridor.Move;
import quoridor.PlayerColour;
import quoridor.QuoridorAction;
import quoridor.QuoridorDisplay;

import java.util.Iterator;

public class AIDecisionMakerSmart extends AbstractDecisionMaker {
	private final static int selectedDepth = 2;
	private PlayerColour maxPlayer;
	
	public AIDecisionMakerSmart(Board board) {
		super(board);
	}
	
	@Override
	public Action getAction() {
		QuoridorDisplay.instance().printBoard(board);
		Move bestMove = null;
		Move nextMove;
		int score;
		int bestScore = Integer.MIN_VALUE;
		maxPlayer = board.currentPlayer();
		MoveSearch moveSearch = new MoveSearch(board);
		int depth = selectedDepth;
		
		if (board.getFenceNum(maxPlayer) == 0) {
			depth = 0;
		}
		Iterator <Move> itr = moveSearch.getMoves().iterator();
		while (itr.hasNext()) {
			nextMove = itr.next();
			score = alphabeta(getChildBoard(board, nextMove), depth, bestScore, Integer.MAX_VALUE, PlayerColour.otherColour(maxPlayer));
			if (score > bestScore) {
				bestScore = score;
				bestMove = nextMove;
			}
		}
		
		return new QuoridorAction(bestMove);
	}
	
	private int alphabeta(Board board, int depth, int alpha, int beta, PlayerColour playerColour) {
		PlayerColour nextPlayer;
		Iterator <Move> itr;
		Move childMove;
		Board childBoard;
		int returnScore;
		boolean pruned = false;
		MoveSearch moveSearch = new MoveSearch(board);
		
		if (depth == 0 || board.isOver()) {
			returnScore = Heuristic.scoreBoard(board, maxPlayer);
		} else {
			switch (playerColour) {
				case BLACK: 
					nextPlayer = PlayerColour.WHITE;
					break;
				case WHITE: 
					nextPlayer = PlayerColour.BLACK;
					break;
				default: 
					nextPlayer = PlayerColour.INVALID;
					break;
			}
			
			if (playerColour.equals(maxPlayer)) {
				itr = moveSearch.getMoves().iterator();
				//for each child of the node
				while(itr.hasNext() && pruned == false) {
				    childMove = (Move) itr.next(); 
				    childBoard = getChildBoard(board, childMove);
				    
				    //use the alpha value of the child nodes
				    alpha = Math.max(alpha, alphabeta(childBoard, depth-1, alpha, beta, nextPlayer));
				    
				    if (beta <= alpha) {
				    	pruned = true;
				    }
				}
				returnScore = alpha;
			} else {	//min player
				
				itr = moveSearch.getMoves().iterator();
				//for each child of the node
				while(itr.hasNext() && pruned == false) {
				    childMove = (Move) itr.next(); 
				    childBoard = getChildBoard(board, childMove);
				    
				    //use the alpha value of the child nodes
				    beta = Math.min(beta, alphabeta(childBoard, depth-1, alpha, beta, nextPlayer));
				    
				    if (beta <= alpha) {
				    	pruned = true;
				    }
				}
				
				returnScore = beta;
			}
		}
		
		return returnScore;
	}

}
